package bancosys.tec.persist.dataset;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;

import bancosys.tec.persist.Persistable;

/**
 * Classe utilizada para paginar os resultados do hibernate na geração de relatórios, evitando assim que todos os resultados estejam na
 * memória ao mesmo tempo. Durante a paginação essa classe permite que o dado seja processado.
 * 
 * @created Apr 25, 2007
 * @author Gustavo Almeida
 * @param <I> tipo devolvido pela query.
 * @param <O> tipo após processamento.
 */
public class HibernateProcessingRandomAccessResultSet<I extends Persistable, O> implements RandomAccessResultSet<O> {
    private RandomAccessResultSet<I> randomResultSet;

    private DataPostProcessor<I, O> dataProcessor;

    /**
     * Construtor.
     * 
     * @param session session do hibernate.
     * @param criteria criteria.
     * @param dataProcessor instancia que irá pós-processar o dado.
     * @param jdbcFetchSize <code>Fetch Size</code> do <code>JDBC</code>.
     * @param pageSize tamanho da página da query.
     * @see Criteria#setFetchSize(int)
     */
    public HibernateProcessingRandomAccessResultSet(Session session, Criteria criteria, DataPostProcessor<I, O> dataProcessor,
            int jdbcFetchSize, int pageSize) {
        this.randomResultSet = new HibernateRandomAccessResultSet<I>(session, criteria, jdbcFetchSize, pageSize);
        this.dataProcessor = dataProcessor;
    }

    /**
     * Construtor.
     * 
     * @param session session do hibernate.
     * @param criteria criteria.
     * @param dataProcessor instancia que irá pós-processar o dado.
     */
    public HibernateProcessingRandomAccessResultSet(Session session, Criteria criteria, DataPostProcessor<I, O> dataProcessor) {
        this.randomResultSet = new HibernateRandomAccessResultSet<I>(session, criteria);
        this.dataProcessor = dataProcessor;
    }

    /**
     * Construtor.
     * 
     * @param session session do hibernate.
     * @param query query.
     * @param dataProcessor instancia que irá pós-processar o dado.
     * @param jdbcFetchSize <code>Fetch Size</code> do <code>JDBC</code>.
     * @param pageSize tamanho da página da query.
     * @see Query#setFetchSize(int)
     */
    public HibernateProcessingRandomAccessResultSet(Session session, Query query, DataPostProcessor<I, O> dataProcessor, int jdbcFetchSize,
            int pageSize) {
        this.randomResultSet = new HibernateRandomAccessResultSet<I>(session, query, jdbcFetchSize, pageSize);
        this.dataProcessor = dataProcessor;
    }

    /**
     * Construtor.
     * 
     * @param session session do hibernate.
     * @param query query.
     * @param dataProcessor instancia que irá pós-processar o dado.
     */
    public HibernateProcessingRandomAccessResultSet(Session session, Query query, DataPostProcessor<I, O> dataProcessor) {
        this.randomResultSet = new HibernateRandomAccessResultSet<I>(session, query);
        this.dataProcessor = dataProcessor;
    }

    /**
     * Construtor.
     * 
     * @param session session do hibernate.
     * @param criteria Criterio da consulta
     * @param dataProcessor instancia que irá pós-processar o dado.
     * @param fieldLazy Lista de atributos para carregar
     */
    public HibernateProcessingRandomAccessResultSet(Session session, Criteria criteria, DataPostProcessor<I, O> dataProcessor,
            String[] fieldLazy)  {
        this.randomResultSet = new HibernateRandomAccessResultSet<I>(session, criteria, fieldLazy);
        
        this.dataProcessor = dataProcessor;
    }
    
    /**
     * Construtor.
     * 
     * @param session session do hibernate.
     * @param query Query hql da consulta
     * @param dataProcessor instancia que irá pós-processar o dado.
     * @param fieldLazy Lista de atributos para carregar
     */
    public HibernateProcessingRandomAccessResultSet(Session session, Query query, DataPostProcessor<I, O> dataProcessor, String[] fieldLazy) {
        this.randomResultSet = new HibernateRandomAccessResultSet<I>(session, query, fieldLazy);
        
        this.dataProcessor = dataProcessor;
    }

    
    /**
     * Devolve o elemento da posição indicada.
     * 
     * @param index posição.
     * @return o elemento da posição indicada.
     */
    public O getObject(int index) {
        I data = this.randomResultSet.getObject(index);
        if (data == null) {
            return null;
        } else {
            return this.dataProcessor.process(data);
        }
    }
}